home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1994 / MacHack 1994.toast / MacHack™ 1987-1994 / MacHack™ '87 / Source ƒ.sea / Source ƒ / emacs source ƒ / DISPLAY.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-28  |  25.4 KB  |  1,126 lines  |  [TEXT/MARC]

  1. /*
  2.  * The functions in this file handle redisplay. There are two halves, the
  3.  * ones that update the virtual display screen, and the ones that make the
  4.  * physical display screen the same as the virtual display screen. These
  5.  * functions use hints that are left in the windows by the commands.
  6.  *
  7.  */
  8.  
  9. #include        <stdio.h>
  10. #include    "estruct.h"
  11. #include        "edef.h"
  12.  
  13. #define WFDEBUG 0                       /* Window flag debug. */
  14.  
  15. typedef struct  VIDEO {
  16.         int    v_flag;                 /* Flags */
  17. #if    COLOR
  18.     int    v_fcolor;        /* current forground color */
  19.     int    v_bcolor;        /* current background color */
  20.     int    v_rfcolor;        /* requested forground color */
  21.     int    v_rbcolor;        /* requested background color */
  22. #endif
  23.         char    v_text[1];              /* Screen data. */
  24. }       VIDEO;
  25.  
  26. #define VFCHG   0x0001                  /* Changed flag            */
  27. #define    VFEXT    0x0002            /* extended (beyond column 80)    */
  28. #define    VFREV    0x0004            /* reverse video status        */
  29. #define    VFREQ    0x0008            /* reverse video request    */
  30. #define    VFCOL    0x0010            /* color change requested    */
  31.  
  32. VIDEO   **vscreen;                      /* Virtual screen. */
  33. #if    ~MEMMAP
  34. VIDEO   **pscreen;                      /* Physical screen. */
  35. #endif
  36.  
  37. /*
  38.  * Initialize the data structures used by the display code. The edge vectors
  39.  * used to access the screens are set up. The operating system's terminal I/O
  40.  * channel is set up. All the other things get initialized at compile time.
  41.  * The original window has "WFCHG" set, so that it will get completely
  42.  * redrawn on the first call to "update".
  43.  */
  44. vtinit()
  45. {
  46.     register int i;
  47.     register VIDEO *vp;
  48.     char *malloc();
  49.  
  50.     (*term.t_open)();        /* open the screen */
  51.     (*term.t_kopen)();        /* open the keyboard */
  52.     (*term.t_rev)(FALSE);
  53.     vscreen = (VIDEO **) malloc(term.t_nrow*sizeof(VIDEO *));
  54.  
  55.     if (vscreen == NULL)
  56.         exit(1);
  57.  
  58. #if    ~MEMMAP
  59.     pscreen = (VIDEO **) malloc(term.t_nrow*sizeof(VIDEO *));
  60.  
  61.     if (pscreen == NULL)
  62.         exit(1);
  63. #endif
  64.  
  65.     for (i = 0; i < term.t_nrow; ++i)
  66.         {
  67.         vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_ncol);
  68.  
  69.         if (vp == NULL)
  70.             exit(1);
  71.  
  72.     vp->v_flag = 0;
  73. #if    COLOR
  74.     vp->v_rfcolor = 7;
  75.     vp->v_rbcolor = 0;
  76. #endif
  77.         vscreen[i] = vp;
  78. #if    ~MEMMAP
  79.         vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_ncol);
  80.  
  81.         if (vp == NULL)
  82.             exit(1);
  83.  
  84.     vp->v_flag = 0;
  85.         pscreen[i] = vp;
  86. #endif
  87.         }
  88. }
  89.  
  90. /*
  91.  * Clean up the virtual terminal system, in anticipation for a return to the
  92.  * operating system. Move down to the last line and clear it out (the next
  93.  * system prompt will be written in the line). Shut down the channel to the
  94.  * terminal.
  95.  */
  96. vttidy()
  97. {
  98.     mlerase();
  99.     movecursor(term.t_nrow, 0);
  100.     (*term.t_flush)();
  101.     (*term.t_close)();
  102.     (*term.t_kclose)();
  103. }
  104.  
  105. /*
  106.  * Set the virtual cursor to the specified row and column on the virtual
  107.  * screen. There is no checking for nonsense values; this might be a good
  108.  * idea during the early stages.
  109.  */
  110. vtmove(row, col)
  111. {
  112.     vtrow = row;
  113.     vtcol = col;
  114. }
  115.  
  116. /*
  117.  * Write a character to the virtual screen. The virtual row and column are
  118.  * updated. If the line is too long put a "$" in the last column. This routine
  119.  * only puts printing characters into the virtual terminal buffers. Only
  120.  * column overflow is checked.
  121.  */
  122. vtputc(c)
  123.     int c;
  124. {
  125.     register VIDEO      *vp;
  126.  
  127.     vp = vscreen[vtrow];
  128.  
  129.     if (vtcol >= term.t_ncol) {
  130.         vtcol = (vtcol + 0x07) & ~0x07;
  131.         vp->v_text[term.t_ncol - 1] = '$';
  132.     } else if (c == '\t')
  133.         {
  134.         do
  135.             {
  136.             vtputc(' ');
  137.             }
  138.         while ((vtcol&0x07) != 0);
  139.         }
  140.     else if (c < 0x20 || c == 0x7F)
  141.         {
  142.         vtputc('^');
  143.         vtputc(c ^ 0x40);
  144.         }
  145.     else
  146.     vp->v_text[vtcol++] = c;
  147. }
  148.  
  149. /*    put a character to the virtual screen in an extended line. If we are
  150.     not yet on left edge, don't print it yet. check for overflow on
  151.     the right margin                        */
  152.  
  153. vtpute(c)
  154.  
  155. int c;
  156.  
  157. {
  158.     register VIDEO      *vp;
  159.  
  160.     vp = vscreen[vtrow];
  161.  
  162.     if (vtcol >= term.t_ncol) {
  163.         vtcol = (vtcol + 0x07) & ~0x07;
  164.         vp->v_text[term.t_ncol - 1] = '$';
  165.     } else if (c == '\t')
  166.         {
  167.         do
  168.             {
  169.             vtpute(' ');
  170.             }
  171.         while (((vtcol + lbound)&0x07) != 0);
  172.         }
  173.     else if (c < 0x20 || c == 0x7F)
  174.         {
  175.         vtpute('^');
  176.         vtpute(c ^ 0x40);
  177.         }
  178.     else {
  179.     if (vtcol >= 0)
  180.         vp->v_text[vtcol] = c;
  181.     ++vtcol;
  182.     }
  183. }
  184.  
  185. /*
  186.  * Erase from the end of the software cursor to the end of the line on which
  187.  * the software cursor is located.
  188.  */
  189. vteeol()
  190. {
  191.     register VIDEO      *vp;
  192.  
  193.     vp = vscreen[vtrow];
  194.     while (vtcol < term.t_ncol)
  195.         vp->v_text[vtcol++] = ' ';
  196. }
  197.  
  198. /* upscreen:    user routine to force a screen update
  199.         always finishes complete update        */
  200.  
  201. upscreen(f, n)
  202.  
  203. {
  204.     update(TRUE);
  205.     return(TRUE);
  206. }
  207.  
  208. /*
  209.  * Make sure that the display is right. This is a three part process. First,
  210.  * scan through all of the windows looking for dirty ones. Check the framing,
  211.  * and refresh the screen. Second, make sure that "currow" and "curcol" are
  212.  * correct for the current window. Third, make the virtual and physical
  213.  * screens the same.
  214.  */
  215. update(force)
  216.  
  217. int force;    /* force update past type ahead? */
  218.  
  219. {
  220.     register WINDOW *wp;
  221.  
  222. #if    TYPEAH
  223.     if (force == FALSE && typahead())
  224.         return(TRUE);
  225. #endif
  226.  
  227.     lflick = 99;    /* check for vertical retrace if needed */
  228.     /* update any windows that need refreshing */
  229.     wp = wheadp;
  230.     while (wp != NULL) {
  231.         if (wp->w_flag) {
  232.             /* if the window has changed, service it */
  233.             reframe(wp);    /* check the framing */
  234.             if ((wp->w_flag & ~WFMODE) == WFEDIT)
  235.                 updone(wp);    /* update EDITed line */
  236.             else if (wp->w_flag & ~WFMOVE)
  237.                 updall(wp);    /* update all lines */
  238. #if    ~WFDEBUG
  239.             if (wp->w_flag & WFMODE)
  240.                 modeline(wp);    /* update modeline */
  241. #endif
  242.             wp->w_flag = 0;
  243.             wp->w_force = 0;
  244.         }
  245. #if    WFDEBUG
  246.         modeline();
  247. #endif
  248.         /* on to the next window */
  249.         wp = wp->w_wndp;
  250.     }
  251.  
  252.     /* recalc the current hardware cursor location */
  253.     updpos();
  254.  
  255. #if    MEMMAP
  256.     /* update the cursor and flush the buffers */
  257.     movecursor(currow, curcol - lbound);
  258. #endif
  259.  
  260.     /* check for lines to de-extend */
  261.     upddex();
  262.  
  263.     /* if screen is garbage, re-plot it */
  264.     if (sgarbf != FALSE)
  265.         updgar();
  266.  
  267.     /* update the virtual screen to the physical screen */
  268.     updupd(force);
  269.  
  270.     /* update the cursor and flush the buffers */
  271.     movecursor(currow, curcol - lbound);
  272.     (*term.t_flush)();
  273.     return(TRUE);
  274. }
  275.  
  276. /*    reframe:    check to see if the cursor is on in the window
  277.             and re-frame it if needed or wanted        */
  278.  
  279. reframe(wp)
  280.  
  281. WINDOW *wp;
  282.  
  283. {
  284.     register LINE *lp;
  285.     register int i;
  286.  
  287.     /* if not a requested reframe, check for a needed one */
  288.     if ((wp->w_flag & WFFORCE) == 0) {
  289.         lp = wp->w_linep;
  290.         for (i = 0; i < wp->w_ntrows; i++) {
  291.  
  292.             /* if the line is in the window, no reframe */
  293.             if (lp == wp->w_dotp)
  294.                 return(TRUE);
  295.  
  296.             /* if we are at the end of the file, reframe */
  297.             if (lp == wp->w_bufp->b_linep)
  298.                 break;
  299.  
  300.             /* on to the next line */
  301.             lp = lforw(lp);
  302.         }
  303.     }
  304.  
  305.     /* reaching here, we need a window refresh */
  306.     i = wp->w_force;
  307.  
  308.     /* how far back to reframe? */
  309.     if (i > 0) {        /* only one screen worth of lines max */
  310.         if (--i >= wp->w_ntrows)
  311.             i = wp->w_ntrows - 1;
  312.     } else if (i < 0) {    /* negative update???? */
  313.         i += wp->w_ntrows;
  314.         if (i < 0)
  315.             i = 0;
  316.     } else
  317.         i = wp->w_ntrows / 2;
  318.  
  319.     /* backup to new line at top of window */
  320.     lp = wp->w_dotp;
  321.     while (i != 0 && lback(lp) != wp->w_bufp->b_linep) {
  322.         --i;
  323.         lp = lback(lp);
  324.     }
  325.  
  326.     /* and reset the current line at top of window */
  327.     wp->w_linep = lp;
  328.     wp->w_flag |= WFHARD;
  329.     wp->w_flag &= ~WFFORCE;
  330.     return(TRUE);
  331. }
  332.  
  333. /*    updone:    update the current line    to the virtual screen        */
  334.  
  335. updone(wp)
  336.  
  337. WINDOW *wp;    /* window to update current line in */
  338.  
  339. {
  340.     register LINE *lp;    /* line to update */
  341.     register int sline;    /* physical screen line to update */
  342.     register int i;
  343.  
  344.     /* search down the line we want */
  345.     lp = wp->w_linep;
  346.     sline = wp->w_toprow;
  347.     while (lp != wp->w_dotp) {
  348.         ++sline;
  349.         lp = lforw(lp);
  350.     }
  351.  
  352.     /* and update the virtual line */
  353.     vscreen[sline]->v_flag |= VFCHG;
  354.     vscreen[sline]->v_flag &= ~VFREQ;
  355.     vtmove(sline, 0);
  356.     for (i=0; i < llength(lp); ++i)
  357.         vtputc(lgetc(lp, i));
  358. #if    COLOR
  359.     vscreen[sline]->v_rfcolor = wp->w_fcolor;
  360.     vscreen[sline]->v_rbcolor = wp->w_bcolor;
  361. #endif
  362.     vteeol();
  363. }
  364.  
  365. /*    updall:    update all the lines in a window on the virtual screen */
  366.  
  367. updall(wp)
  368.  
  369. WINDOW *wp;    /* window to update lines in */
  370.  
  371. {
  372.     register LINE *lp;    /* line to update */
  373.     register int sline;    /* physical screen line to update */
  374.     register int i;
  375.  
  376.     /* search down the lines, updating them */
  377.     lp = wp->w_linep;
  378.     sline = wp->w_toprow;
  379.     while (sline < wp->w_toprow + wp->w_ntrows) {
  380.  
  381.         /* and update the virtual line */
  382.         vscreen[sline]->v_flag |= VFCHG;
  383.         vscreen[sline]->v_flag &= ~VFREQ;
  384.         vtmove(sline, 0);
  385.         if (lp != wp->w_bufp->b_linep) {
  386.             /* if we are not at the end */
  387.             for (i=0; i < llength(lp); ++i)
  388.                 vtputc(lgetc(lp, i));
  389.             lp = lforw(lp);
  390.         }
  391.  
  392.         /* on to the next one */
  393. #if    COLOR
  394.         vscreen[sline]->v_rfcolor = wp->w_fcolor;
  395.         vscreen[sline]->v_rbcolor = wp->w_bcolor;
  396. #endif
  397.         vteeol();
  398.         ++sline;
  399.     }
  400.  
  401. }
  402.  
  403. /*    updpos:    update the position of the hardware cursor and handle extended
  404.         lines. This is the only update for simple moves.    */
  405.  
  406. updpos()
  407.  
  408. {
  409.     register LINE *lp;
  410.     register int c;
  411.     register int i;
  412.  
  413.     /* find the current row */
  414.     lp = curwp->w_linep;
  415.     currow = curwp->w_toprow;
  416.     while (lp != curwp->w_dotp) {
  417.         ++currow;
  418.         lp = lforw(lp);
  419.     }
  420.  
  421.     /* find the current column */
  422.     curcol = 0;
  423.     i = 0;
  424.     while (i < curwp->w_doto) {
  425.         c = lgetc(lp, i++);
  426.         if (c == '\t')
  427.             curcol |= 0x07;
  428.         else
  429.             if (c < 0x20 || c == 0x7f)
  430.                 ++curcol;
  431.  
  432.         ++curcol;
  433.     }
  434.  
  435.     /* if extended, flag so and update the virtual line image */
  436.     if (curcol >=  term.t_ncol - 1) {
  437.         vscreen[currow]->v_flag |= (VFEXT | VFCHG);
  438.         updext();
  439.     } else
  440.         lbound = 0;
  441. }
  442.  
  443. /*    upddex:    de-extend any line that derserves it        */
  444.  
  445. upddex()
  446.  
  447. {
  448.     register WINDOW *wp;
  449.     register LINE *lp;
  450.     register int i,j;
  451.  
  452.     wp = wheadp;
  453.  
  454.     while (wp != NULL) {
  455.         lp = wp->w_linep;
  456.         i = wp->w_toprow;
  457.  
  458.         while (i < wp->w_toprow + wp->w_ntrows) {
  459.             if (vscreen[i]->v_flag & VFEXT) {
  460.                 if ((wp != curwp) || (lp != wp->w_dotp) ||
  461.                    (curcol < term.t_ncol - 1)) {
  462.                     vtmove(i, 0);
  463.                     for (j = 0; j < llength(lp); ++j)
  464.                         vtputc(lgetc(lp, j));
  465.                     vteeol();
  466.  
  467.                     /* this line no longer is extended */
  468.                     vscreen[i]->v_flag &= ~VFEXT;
  469.                     vscreen[i]->v_flag |= VFCHG;
  470.                 }
  471.             }
  472.             lp = lforw(lp);
  473.             ++i;
  474.         }
  475.         /* and onward to the next window */
  476.         wp = wp->w_wndp;
  477.     }
  478. }
  479.  
  480. /*    updgar:    if the screen is garbage, clear the physical screen and
  481.         the virtual screen and force a full update        */
  482.  
  483. updgar()
  484.  
  485. {
  486.     register char *txt;
  487.     register int i,j;
  488.  
  489.     for (i = 0; i < term.t_nrow; ++i) {
  490.         vscreen[i]->v_flag |= VFCHG;
  491. #if    REVSTA
  492.         vscreen[i]->v_flag &= ~VFREV;
  493. #endif
  494. #if    COLOR
  495.         vscreen[i]->v_fcolor = gfcolor;
  496.         vscreen[i]->v_bcolor = gbcolor;
  497. #endif
  498. #if    ~MEMMAP
  499.         txt = pscreen[i]->v_text;
  500.         for (j = 0; j < term.t_ncol; ++j)
  501.             txt[j] = ' ';
  502. #endif
  503.     }
  504.  
  505.     movecursor(0, 0);         /* Erase the screen. */
  506.     (*term.t_eeop)();
  507.     sgarbf = FALSE;             /* Erase-page clears */
  508.     mpresf = FALSE;             /* the message area. */
  509. #if    COLOR
  510.     mlerase();            /* needs to be cleared if colored */
  511. #endif
  512. }
  513.  
  514. /*    updupd:    update the physical screen from the virtual screen    */
  515.  
  516. updupd(force)
  517.  
  518. int force;    /* forced update flag */
  519.  
  520. {
  521.     register VIDEO *vp1;
  522.     register int i;
  523.  
  524.     for (i = 0; i < term.t_nrow; ++i) {
  525.         vp1 = vscreen[i];
  526.  
  527.         /* for each line that needs to be updated*/
  528.         if ((vp1->v_flag & VFCHG) != 0) {
  529. #if    TYPEAH
  530.             if (force == FALSE && typahead())
  531.                 return(TRUE);
  532. #endif
  533. #if    MEMMAP
  534.             updateline(i, vp1);
  535. #else
  536.             updateline(i, vp1, pscreen[i]);
  537. #endif
  538.         }
  539.     }
  540.     return(TRUE);
  541. }
  542.  
  543. /*    updext: update the extended line which the cursor is currently
  544.         on at a column greater than the terminal width. The line
  545.         will be scrolled right or left to let the user see where
  546.         the cursor is
  547.                                 */
  548.  
  549. updext()
  550.  
  551. {
  552.     register int rcursor;    /* real cursor location */
  553.     register LINE *lp;    /* pointer to current line */
  554.     register int j;        /* index into line */
  555.  
  556.     /* calculate what column the real cursor will end up in */
  557.     rcursor = ((curcol - term.t_ncol) % term.t_scrsiz) + term.t_margin;
  558.     lbound = curcol - rcursor + 1;
  559.  
  560.     /* scan through the line outputing characters to the virtual screen */
  561.     /* once we reach the left edge                    */
  562.     vtmove(currow, -lbound);    /* start scanning offscreen */
  563.     lp = curwp->w_dotp;        /* line to output */
  564.     for (j=0; j<llength(lp); ++j)    /* until the end-of-line */
  565.         vtpute(lgetc(lp, j));
  566.  
  567.     /* truncate the virtual line */
  568.     vteeol();
  569.  
  570.     /* and put a '$' in column 1 */
  571.     vscreen[currow]->v_text[0] = '$';
  572. }
  573.  
  574. /*
  575.  * Update a single line. This does not know how to use insert or delete
  576.  * character sequences; we are using VT52 functionality. Update the physical
  577.  * row and column variables. It does try an exploit erase to end of line. The
  578.  * RAINBOW version of this routine uses fast video.
  579.  */
  580. #if    MEMMAP
  581. /*    UPDATELINE specific code for the IBM-PC and other compatables */
  582.  
  583. updateline(row, vp1)
  584.  
  585. int row;        /* row of screen to update */
  586. struct VIDEO *vp1;    /* virtual screen image */
  587.  
  588. {
  589. #if    COLOR
  590.     scwrite(row, vp1->v_text, vp1->v_rfcolor, vp1->v_rbcolor);
  591.     vp1->v_fcolor = vp1->v_rfcolor;
  592.     vp1->v_bcolor = vp1->v_rbcolor;
  593. #else
  594.     if (vp1->v_flag & VFREQ)
  595.         scwrite(row, vp1->v_text, 0, 7);
  596.     else
  597.         scwrite(row, vp1->v_text, 7, 0);
  598. #endif
  599.     vp1->v_flag &= ~(VFCHG | VFCOL);    /* flag this line as changed */
  600.  
  601. }
  602.  
  603. #else
  604.  
  605. updateline(row, vp1, vp2)
  606.  
  607. int row;        /* row of screen to update */
  608. struct VIDEO *vp1;    /* virtual screen image */
  609. struct VIDEO *vp2;    /* physical screen image */
  610.  
  611. {
  612. #if RAINBOW
  613. /*    UPDATELINE specific code for the DEC rainbow 100 micro    */
  614.  
  615.     register char *cp1;
  616.     register char *cp2;
  617.     register int nch;
  618.  
  619.     /* since we don't know how to make the rainbow do this, turn it off */
  620.     flags &= (~VFREV & ~VFREQ);
  621.  
  622.     cp1 = &vp1->v_text[0];                    /* Use fast video. */
  623.     cp2 = &vp2->v_text[0];
  624.     putline(row+1, 1, cp1);
  625.     nch = term.t_ncol;
  626.  
  627.     do
  628.         {
  629.         *cp2 = *cp1;
  630.         ++cp2;
  631.         ++cp1;
  632.         }
  633.     while (--nch);
  634.     *flags &= ~VFCHG;
  635. #else
  636. /*    UPDATELINE code for all other versions        */
  637.  
  638.     register char *cp1;
  639.     register char *cp2;
  640.     register char *cp3;
  641.     register char *cp4;
  642.     register char *cp5;
  643.     register int nbflag;    /* non-blanks to the right flag? */
  644.     int rev;        /* reverse video flag */
  645.     int req;        /* reverse video request flag */
  646.  
  647.  
  648.     /* set up pointers to virtual and physical lines */
  649.     cp1 = &vp1->v_text[0];
  650.     cp2 = &vp2->v_text[0];
  651.  
  652. #if    COLOR
  653.     (*term.t_setfor)(vp1->v_rfcolor);
  654.     (*term.t_setback)(vp1->v_rbcolor);
  655. #endif
  656.  
  657. #if    REVSTA | COLOR
  658.     /* if we need to change the reverse video status of the
  659.        current line, we need to re-write the entire line     */
  660.     rev = (vp1->v_flag & VFREV) == VFREV;
  661.     req = (vp1->v_flag & VFREQ) == VFREQ;
  662.     if ((rev != req)
  663. #if    COLOR
  664.         || (vp1->v_fcolor != vp1->v_rfcolor) || (vp1->v_bcolor != vp1->v_rbcolor)
  665. #endif
  666. #if    HP150
  667.     /* the HP150 has some reverse video problems */
  668.         || req || rev
  669. #endif
  670.             ) {
  671.         movecursor(row, 0);    /* Go to start of line. */
  672.         /* set rev video if needed */
  673.         if (rev != req)
  674.             (*term.t_rev)(req);
  675.  
  676.         /* scan through the line and dump it to the screen and
  677.            the virtual screen array                */
  678.         cp3 = &vp1->v_text[term.t_ncol];
  679.         while (cp1 < cp3) {
  680.             (*term.t_putchar)(*cp1);
  681.             ++ttcol;
  682.             *cp2++ = *cp1++;
  683.         }
  684.         /* turn rev video off */
  685.         if (rev != req)
  686.             (*term.t_rev)(FALSE);
  687.  
  688.         /* update the needed flags */
  689.         vp1->v_flag &= ~VFCHG;
  690.         if (req)
  691.             vp1->v_flag |= VFREV;
  692.         else
  693.             vp1->v_flag &= ~VFREV;
  694. #if    COLOR
  695.         vp1->v_fcolor = vp1->v_rfcolor;
  696.         vp1->v_bcolor = vp1->v_rbcolor;
  697. #endif
  698.         return(TRUE);
  699.     }
  700. #endif
  701.  
  702.     /* advance past any common chars at the left */
  703.     while (cp1 != &vp1->v_text[term.t_ncol] && cp1[0] == cp2[0]) {
  704.         ++cp1;
  705.         ++cp2;
  706.     }
  707.  
  708. /* This can still happen, even though we only call this routine on changed
  709.  * lines. A hard update is always done when a line splits, a massive
  710.  * change is done, or a buffer is displayed twice. This optimizes out most
  711.  * of the excess updating. A lot of computes are used, but these tend to
  712.  * be hard operations that do a lot of update, so I don't really care.
  713.  */
  714.     /* if both lines are the same, no update needs to be done */
  715.     if (cp1 == &vp1->v_text[term.t_ncol]) {
  716.          vp1->v_flag &= ~VFCHG;        /* flag this line is changed */
  717.         return(TRUE);
  718.     }
  719.  
  720.     /* find out if there is a match on the right */
  721.     nbflag = FALSE;
  722.     cp3 = &vp1->v_text[term.t_ncol];
  723.     cp4 = &vp2->v_text[term.t_ncol];
  724.  
  725.     while (cp3[-1] == cp4[-1]) {
  726.         --cp3;
  727.         --cp4;
  728.         if (cp3[0] != ' ')        /* Note if any nonblank */
  729.             nbflag = TRUE;        /* in right match. */
  730.     }
  731.  
  732.     cp5 = cp3;
  733.  
  734.     /* Erase to EOL ? */
  735.     if (nbflag == FALSE && eolexist == TRUE && (req != TRUE)) {
  736.         while (cp5!=cp1 && cp5[-1]==' ')
  737.             --cp5;
  738.  
  739.         if (cp3-cp5 <= 3)        /* Use only if erase is */
  740.             cp5 = cp3;        /* fewer characters. */
  741.     }
  742.  
  743.     movecursor(row, cp1 - &vp1->v_text[0]);    /* Go to start of line. */
  744. #if    REVSTA
  745.     (*term.t_rev)(rev);
  746. #endif
  747.  
  748.     while (cp1 != cp5) {        /* Ordinary. */
  749.         (*term.t_putchar)(*cp1);
  750.         ++ttcol;
  751.         *cp2++ = *cp1++;
  752.     }
  753.  
  754.     if (cp5 != cp3) {        /* Erase. */
  755.         (*term.t_eeol)();
  756.         while (cp1 != cp3)
  757.             *cp2++ = *cp1++;
  758.     }
  759. #if    REVSTA
  760.     (*term.t_rev)(FALSE);
  761. #endif
  762.     vp1->v_flag &= ~VFCHG;        /* flag this line as updated */
  763.     return(TRUE);
  764. #endif
  765. }
  766. #endif
  767.  
  768. /*
  769.  * Redisplay the mode line for the window pointed to by the "wp". This is the
  770.  * only routine that has any idea of how the modeline is formatted. You can
  771.  * change the modeline format by hacking at this routine. Called by "update"
  772.  * any time there is a dirty window.
  773.  */
  774. modeline(wp)
  775.     WINDOW *wp;
  776. {
  777.     register char *cp;
  778.     register int c;
  779.     register int n;        /* cursor position count */
  780.     register BUFFER *bp;
  781.     register i;            /* loop index */
  782.     register lchar;        /* character to draw line in buffer with */
  783.     register firstm;        /* is this the first mode? */
  784.     char tline[NLINE];        /* buffer for part of mode line */
  785.  
  786.     n = wp->w_toprow+wp->w_ntrows;          /* Location. */
  787.     vscreen[n]->v_flag |= VFCHG | VFREQ | VFCOL;/* Redraw next time. */
  788. #if    COLOR
  789.     vscreen[n]->v_rfcolor = 0;            /* black on */
  790.     vscreen[n]->v_rbcolor = 7;            /* white.....*/
  791. #endif
  792.     vtmove(n, 0);                           /* Seek to right line. */
  793.     if (wp == curwp)                /* mark the current buffer */
  794.     lchar = '=';
  795.     else
  796. #if    REVSTA
  797.     if (revexist)
  798.         lchar = ' ';
  799.     else
  800. #endif
  801.         lchar = '-';
  802.  
  803.     vtputc(lchar);
  804.     bp = wp->w_bufp;
  805.  
  806.     if ((bp->b_flag&BFCHG) != 0)                /* "*" if changed. */
  807.         vtputc('*');
  808.     else
  809.         vtputc(lchar);
  810.  
  811.     n  = 2;
  812.     strcpy(tline, " MicroEMACS ");        /* Buffer name. */
  813.     strcat(tline, VERSION);
  814.     strcat(tline, " (");
  815.  
  816.     /* display the modes */
  817.  
  818.     firstm = TRUE;
  819.     for (i = 0; i < NUMMODES; i++)    /* add in the mode flags */
  820.         if (wp->w_bufp->b_mode & (1 << i)) {
  821.             if (firstm != TRUE)
  822.                 strcat(tline, " ");
  823.             firstm = FALSE;
  824.             strcat(tline, modename[i]);
  825.         }
  826.     strcat(tline,") ");
  827.  
  828.     cp = &tline[0];
  829.     while ((c = *cp++) != 0)
  830.         {
  831.         vtputc(c);
  832.         ++n;
  833.         }
  834.  
  835. #if WFDEBUG
  836.     vtputc(lchar);
  837.     vtputc((wp->w_flag&WFCOLR) != 0  ? 'C' : lchar);
  838.     vtputc((wp->w_flag&WFMODE) != 0  ? 'M' : lchar);
  839.     vtputc((wp->w_flag&WFHARD) != 0  ? 'H' : lchar);
  840.     vtputc((wp->w_flag&WFEDIT) != 0  ? 'E' : lchar);
  841.     vtputc((wp->w_flag&WFMOVE) != 0  ? 'V' : lchar);
  842.     vtputc((wp->w_flag&WFFORCE) != 0 ? 'F' : lchar);
  843.     vtputc(lchar);
  844.     n += 8;
  845. #endif
  846.  
  847.     vtputc(lchar);
  848.     vtputc(lchar);
  849.     vtputc(' ');
  850.     n += 3;
  851.     cp = &bp->b_bname[0];
  852.  
  853.     while ((c = *cp++) != 0)
  854.         {
  855.         vtputc(c);
  856.         ++n;
  857.         }
  858.  
  859.     vtputc(' ');
  860.     vtputc(lchar);
  861.     vtputc(lchar);
  862.     n += 3;
  863.  
  864.     if (bp->b_fname[0] != 0)            /* File name. */
  865.         {
  866.     vtputc(' ');
  867.     ++n;
  868.         cp = "File: ";
  869.  
  870.         while ((c = *cp++) != 0)
  871.             {
  872.             vtputc(c);
  873.             ++n;
  874.             }
  875.  
  876.         cp = &bp->b_fname[0];
  877.  
  878.         while ((c = *cp++) != 0)
  879.             {
  880.             vtputc(c);
  881.             ++n;
  882.             }
  883.  
  884.         vtputc(' ');
  885.         ++n;
  886.         }
  887.  
  888.     while (n < term.t_ncol)             /* Pad to full width. */
  889.         {
  890.         vtputc(lchar);
  891.         ++n;
  892.         }
  893. }
  894.  
  895. upmode()    /* update all the mode lines */
  896.  
  897. {
  898.     register WINDOW *wp;
  899.  
  900.     wp = wheadp;
  901.     while (wp != NULL) {
  902.         wp->w_flag |= WFMODE;
  903.         wp = wp->w_wndp;
  904.     }
  905. }
  906.  
  907. /*
  908.  * Send a command to the terminal to move the hardware cursor to row "row"
  909.  * and column "col". The row and column arguments are origin 0. Optimize out
  910.  * random calls. Update "ttrow" and "ttcol".
  911.  */
  912. movecursor(row, col)
  913.     {
  914.     if (row!=ttrow || col!=ttcol)
  915.         {
  916.         ttrow = row;
  917.         ttcol = col;
  918.         (*term.t_move)(row, col);
  919.         }
  920.     }
  921.  
  922. /*
  923.  * Erase the message line. This is a special routine because the message line
  924.  * is not considered to be part of the virtual screen. It always works
  925.  * immediately; the terminal buffer is flushed via a call to the flusher.
  926.  */
  927. mlerase()
  928.     {
  929.     int i;
  930.     
  931.     movecursor(term.t_nrow, 0);
  932. #if    COLOR
  933.      (*term.t_setfor)(7);
  934.      (*term.t_setback)(0);
  935. #endif
  936.     if (eolexist == TRUE)
  937.         (*term.t_eeol)();
  938.     else {
  939.         for (i = 0; i < term.t_ncol - 1; i++)
  940.             (*term.t_putchar)(' ');
  941.         movecursor(term.t_nrow, 1);    /* force the move! */
  942.         movecursor(term.t_nrow, 0);
  943.     }
  944.     (*term.t_flush)();
  945.     mpresf = FALSE;
  946.     }
  947.  
  948. /*
  949.  * Write a message into the message line. Keep track of the physical cursor
  950.  * position. A small class of printf like format items is handled. Assumes the
  951.  * stack grows down; this assumption is made by the "++" in the argument scan
  952.  * loop. Set the "message line" flag TRUE.
  953.  */
  954.  
  955. mlwrite(fmt, arg)
  956.     char *fmt;
  957.     {
  958.     register int c;
  959.     register char *ap;
  960.  
  961. #if    COLOR
  962.     (*term.t_setfor)(7);
  963.     (*term.t_setback)(0);
  964. #endif
  965.     if (eolexist == FALSE) {
  966.         mlerase();
  967.         (*term.t_flush)();
  968.     }
  969.  
  970.     movecursor(term.t_nrow, 0);
  971.     ap = (char *) &arg;
  972.     while ((c = *fmt++) != 0) {
  973.         if (c != '%') {
  974.             (*term.t_putchar)(c);
  975.             ++ttcol;
  976.             }
  977.         else
  978.             {
  979.             c = *fmt++;
  980.             switch (c) {
  981.                 case 'd':
  982.                     mlputi(*(int *)ap, 10);
  983.                     ap += sizeof(int);
  984.                     break;
  985.  
  986.                 case 'o':
  987.                     mlputi(*(int *)ap,  8);
  988.                     ap += sizeof(int);
  989.                     break;
  990.  
  991.                 case 'x':
  992.                     mlputi(*(int *)ap, 16);
  993.                     ap += sizeof(int);
  994.                     break;
  995.  
  996.                 case 'D':
  997.                     mlputli(*(long *)ap, 10);
  998.                     ap += sizeof(long);
  999.                     break;
  1000.  
  1001.                 case 's':
  1002.                     mlputs(*(char **)ap);
  1003.                     ap += sizeof(char *);
  1004.                     break;
  1005.  
  1006.         case 'f':
  1007.             mlputf(*(int *)ap);
  1008.             ap += sizeof(int);
  1009.             break;
  1010.  
  1011.                 default:
  1012.                     (*term.t_putchar)(c);
  1013.                     ++ttcol;
  1014.                 }
  1015.             }
  1016.         }
  1017.     if (eolexist == TRUE)
  1018.         (*term.t_eeol)();
  1019.     (*term.t_flush)();
  1020.     mpresf = TRUE;
  1021.     }
  1022.  
  1023. /*
  1024.  * Write out a string. Update the physical cursor position. This assumes that
  1025.  * the characters in the string all have width "1"; if this is not the case
  1026.  * things will get screwed up a little.
  1027.  */
  1028. mlputs(s)
  1029.     char *s;
  1030.     {
  1031.     register int c;
  1032.  
  1033.     while ((c = *s++) != 0)
  1034.         {
  1035.         (*term.t_putchar)(c);
  1036.         ++ttcol;
  1037.         }
  1038.     }
  1039.  
  1040. /*
  1041.  * Write out an integer, in the specified radix. Update the physical cursor
  1042.  * position.
  1043.  */
  1044. mlputi(i, r)
  1045.     {
  1046.     register int q;
  1047.     static char hexdigits[] = "0123456789ABCDEF";
  1048.  
  1049.     if (i < 0)
  1050.         {
  1051.         i = -i;
  1052.         (*term.t_putchar)('-');
  1053.         }
  1054.  
  1055.     q = i/r;
  1056.  
  1057.     if (q != 0)
  1058.         mlputi(q, r);
  1059.  
  1060.     (*term.t_putchar)(hexdigits[i%r]);
  1061.     ++ttcol;
  1062.     }
  1063.  
  1064. /*
  1065.  * do the same except as a long integer.
  1066.  */
  1067. mlputli(l, r)
  1068.     long l;
  1069.     {
  1070.     register long q;
  1071.  
  1072.     if (l < 0)
  1073.         {
  1074.         l = -l;
  1075.         (*term.t_putchar)('-');
  1076.         }
  1077.  
  1078.     q = l/r;
  1079.  
  1080.     if (q != 0)
  1081.         mlputli(q, r);
  1082.  
  1083.     (*term.t_putchar)((int)(l%r)+'0');
  1084.     ++ttcol;
  1085.     }
  1086.  
  1087. /*
  1088.  *    write out a scaled integer with two decimal places
  1089.  */
  1090.  
  1091. mlputf(s)
  1092.  
  1093. int s;    /* scaled integer to output */
  1094.  
  1095. {
  1096.     int i;    /* integer portion of number */
  1097.     int f;    /* fractional portion of number */
  1098.  
  1099.     /* break it up */
  1100.     i = s / 100;
  1101.     f = s % 100;
  1102.  
  1103.     /* send out the integer portion */
  1104.     mlputi(i, 10);
  1105.     (*term.t_putchar)('.');
  1106.     (*term.t_putchar)((f / 10) + '0');
  1107.     (*term.t_putchar)((f % 10) + '0');
  1108.     ttcol += 3;
  1109. }    
  1110.  
  1111. #if RAINBOW
  1112.  
  1113. putline(row, col, buf)
  1114.     int row, col;
  1115.     char buf[];
  1116.     {
  1117.     int n;
  1118.  
  1119.     n = strlen(buf);
  1120.     if (col + n - 1 > term.t_ncol)
  1121.         n = term.t_ncol - col + 1;
  1122.     Put_Data(row, col, n, buf);
  1123.     }
  1124. #endif
  1125.  
  1126.